Zabezpieczenie programu jest na tyle ciekawe, ze warto sie nim zajac :-) Wstepne zapoznanie sie z celem prowadzi do kilku wnioskow:
- podczas uruchamiania pojawia sie okropny nag-screen z wielkim napisem 'NOT REGISTERED' i trzema przyciskami, z ktorych tylko jeden (losowo wybrany) pozwala uruchomic program,
- po trafieniu w porzadany przycisk, obok nazwy programu, widzimy rownie piekny napis 'NOT REGISTERED',
- nigdzie nie mozemy znalezc okienka rejestracyjnego, czyli zabezpieczenie najpradopodobniej oparte jest na brakujacym pliku.
Jak sie zaraz okaze, uporanie sie z powyzszymi problemami ;-) nie jest az tak ciezkie. Klopot pojawia sie jednak, gdy chcemy wprowadzic jakies zmiany w wincmd32.exe. Wtedy to pojawia sie ostrzezenie, ze plik zostal zaifekowany i program konczy swoje dzialanie :-(. Calkiem ciekawie :-0.
Wrocmy jednak do naszego brakujacego pliku. Sprobujmy sprawdzic, czy nasze przypuszczenia byly sluszne. W SI zakladamymy wiec pulapke:
bpx CreateFileA do "d esp->4; p ret;"
i uruchamiamy wincmd32.exe. Jak zaraz zobaczymy, najpierw otwarty zostanie plik wincmd32.exe (wow!), a po kilku kolejnych zatrzymaniach dojdziemy do momentu, w ktorym otwrty zostac ma plik wincmd.key. Tak, to bez watpienia nasz brakujacy plik! Od razu jednak zaznaczam, ze nie bede sie staral dojsc do tego, co w nim sie powinno znalezc, bo jest to zakrecone jak sloiki z dzemem mojej babci. Jezeli jednak komus uda sie rozpracowac sposob kodowania danych w wincmd.key, niech do mnie napisze (iwy@friko.onet.pl).
OK, przejdzmy wiec do konkretow. Nasza pulapka zatrzymala wykonywanie programu w momencie proby otwarcia wincmd.key:
:00442148 Call KERNEL32!CreateFileA
:0044214D mov dword ptr [ebp-1C], eax <-- TUTAJ!
:00442150 cmp dword ptr [ebp-1C], FFFFFFFF
:00442154 jnz 0044216C
:00442156 call 00403508
:0044215B lea eax, dword ptr [eax+0000000C]
:00442161 push eax
Skok w :00442154 nie zostaje wykonany, poniewaz eax=-1 (nie ma pliku, wiec -1 trafia do eax). Jedziemy wiec dalej, az do momentu, gdy skok:
:004BED99 jnz 004BEDBC
doprowadza nas do fragmentu:
:004BEDBC xor ebx, ebx
:004BEDBE mov [ebp-1E], 0000
:004BEDC7 cmp word ptr [ebp-1E], 0080
:004BEDD0 setz byte ptr [005181FD]
W drugiej linijce tego fragmentu 0 oznacza, ze nie ma pliku wincmd.key. Porownanie linijke nizej sprawdza, czy plik istnieje (odwoluje sie do niej skok z linii :004BEDBA) i jezeli istnieje, ustawiana jest flaga zerowa pod adresem [005187FD]. Idzmy wiec dalej tym tropem. Zlikwidujmy nasza aktywna pulapke i zalozmy nowa, ktora pilnowac bede naszej flagi zerowej:
bpm 5187FD rw
F5 doprowadzi nas do:
:004BEDD7 test bl, bl
:004BEDDE je 004BF0D0
a wiec do dalszej czesci powyzszego kodu. Jeszcze raz F5 i:
:004BF714 mov al, byte ptr [005187FD]
:004BF719 ret
...powrot z funkcji...
:004BCD85 test al, al
:004BCD87 jz 004BCDC9
...skok do...
:004BCDC9 call 004BF70C
...wywolanie...
:004BF70C mov al, byte ptr [005187FC]
:004BF711 ret
...powrot z funkcji...
:004BCDCE test al, al
:004BCDD0 jz 004BCDF8
No, ale zamieszanie! Sprobujmy jednak przanalizowac to ze spokojem. W al nie pojawia sie 1, wiec skok pod :004BCD87 zostaje wykonany (nie ma wincmd.key). Dochodzimy wiec do funkcji, ktora powoduje skopiowanie 0 do al (flaga zerowa nie zostala przeciez ustawiona). Dlatego tez skok pod :004BCDD0 zostaje wykonany. A za co on odpowiada? Tak, za pojawienie sie nag-screen'a, a wlasciwie jego niemilej wersji (jak sie pozniej okaze pojawia sie in na moment rowniez po zarejstrowaniu programu tyle, ze bez przyciskow i z napisem 'iwan / CrackPL'.
Aby wiec nie zobaczyc nag-screen'a, bedac w linii :004BCDCE mozemy napisac:
R eip=004BCDD2
F5 i... nagscreen przeskoczony. Pozniej usuniemy skok w :004BCDD0, warto wiec go zapamietac (offset BC1D0).
Czas teraz zabrac sie za 'NOT REGISTERED'. Szybko zauwazymy, ze nie mozna go w zaden sposob znalezc przy uzyciu hiew. Ani kawalka 'NOT REGISTERED', 'N O T R E G I S T E R E D' ani zadnej innej kombinacji. Na tak, pewno jest jakos zakodowany :-0. Szukamy wiec w pamieci wszystkich sladow tego ciagu:
S 30:0 l ffffffff 'NOT REG'
Jako, ze pojawia sie on kilka razy, musimy cierpliwe pozakladac kilka BPR. U mnie owocny okazal sie jeden:
BPR 30:00C02178 30:00C02185 RW
ktory to doprowadzil mnie do call'a wywolujacego taki fragment:
:00409B98 mov edx, eax
:00409B9A jmp 00409BAF
:00409B9C cmp cl, 0A <-----------
:00409B9F je 00409BAE |
:00409BA1 mov cl, byte ptr [edx] |
:00409BA3 sub cl, 20 |
:00409BA6 xor cl, 77 |
:00409BA9 add cl, 20 |
:00409BAC mov byte ptr [edx], cl |
:00409BAE inc edx |
:00409BAF mov cl, byte ptr [edx] |
:00409BB1 test cl, cl |
:00409BB3 jne 00409B9C -----------
:00409BB5 ret
Coz, jak widac nie jest to nic innego, jak intereujaca nas procedura szyfrujaca. Z EDX kopiowane sa kolejne znaki ciagu 'NOT REGISTERED' i po zaszyfrowaniu wracaja na swoje miejsce. Samo szyfrowanie jest proste - od wartosci hex znaku odejmowane jest 20, wynik XORowany jest z 77 i zsumowany z 20. Jezeli wiec ciag 'NOT REGISTERED' chcemy zastapic przez 'iwan / CrackPL', musimy go zakodowac w ten sam sposob. Ostatecznie zmienimy wiec ciag:
79 78 63 97 65 72 70 7E 64 63 72 65 72 73
na:
5E 40 56 59 97 98 97 74 45 56 54 5C 67 7B
Pomoze nam w tym oczywi£cie Hiew ;-)
OK, pieknie - nie mamy juz nag-screen'a, napisu 'NOT REGISTERED', ktorego miejsce zajela nasza ksywa :-). Pozostal jeszcze tylko jeden maly problem - komunikat o wirusie:
"WARNING: The WINCMD executable file is corrupted, possible VIRUS! Wincmd will close. Please run a virus scanner as soon as possible!"
Ok, wrocmy wiec do poczatku naszej analizy. Ustawiamy wiec:
bpx CreateFileA do "d esp->4; p ret;"
jeszcze raz. Analize kodu rozpoczynamy, gdy wyladujemy w kodzie programu w momencie otwarcia pliku windcm32.exe (juz po pojawieniu sie zmodyfikowanego nag-screen'a). Cierpliwa analiza doprowadza nas do tekiego fragmentu kodu:
:0044F042 xor ecx, ecx
:0044F044 mov cl, byte ptr [edi]
:0044F046 add eax, ecx
:0044F048 add edx, eax
:0044F04A inc edi
:0044F04B dec esi
:0044F04C jne 0044F044
:0044F04E mov dword ptr [ebp-04], eax
:0044F051 mov dword ptr [ebp-08], edx
:0044F054 pop esi
:0044F055 pop edi
:0044F056 mov eax, dword ptr [edi]
:0044F058 add dword ptr [ebp-0C], eax
:0044F05B mov eax, dword ptr [ebp-04]
:0044F05E mov ecx, 0000FFF1
:0044F063 cdq
:0044F064 idiv ecx
:0044F066 mov dword ptr [ebp-04], edx
:0044F069 mov eax, dword ptr [ebp-08]
:0044F06C mov ecx, 0000FFF1
:0044F071 cdq
:0044F072 idiv ecx
:0044F074 mov dword ptr [ebp-08], edx
:0044F077 test ebx, ebx
:0044F079 jg 0044F01C
:0044F07B mov eax, dword ptr [ebp-08]
:0044F07E shl eax, 10
:0044F081 or eax, dword ptr [ebp-04]
:0044F084 mov dword ptr [esi], eax
Ten fragment kodu odpowiada za obliczenie tzw. checksum, ktora ostatecznie laduje pod adresem wskazywanym przez esi (w tym przypadku jest to 006DF93C). Analize samego sposobu liczenia checksum pozostawiam dociekliwym, ja w tym tutorialu nie bede sie tym zajmowal, bo nie jest to potrzebne :-) (jezeli bardzo Ci zalezy, napisz do mnie, to podpowiem). W tym momencie najwazniejsze, ze wiemy, gdzie checksum jest zapisywana. Zalozmy wiec pulapke na dostepie do pamieci w tym miejscu, usuwajac wczesniej poprzednie pulapki:
bpmd 157:006DF93C rw
Po wyjsciu z petli dochodzimy w koncu do miejsca, w ktorym nasza checksum jest XORowana z wartoscia F5A3E289 i zapisana w eax. Nastepnie jest ona porownywana z prawidlowa wartoscia (czyli taka, jaka powinna byc, gdyby w pliku nie zostaly dokonane zadne zmiany):
:0045024A mov eax, dword ptr [ebp+08]
:0045024D xor dword ptr [eax-04], F5A3E289
:00450254 push ebp
:00450255 call 00450114
...i po wywolaniu...
:00450114 push ebp
:00450115 mov ebp, esp
:00450117 mov eax, dword ptr [ebp+08]
:0045011A mov eax, dword ptr [eax+08]
:0045011D mov eax, dword ptr [eax-04]
:00450120 mov edx, dword ptr [ebp+08]
:00450123 mov edx, dword ptr [edx+08]
:00450126 cmp eax, dword ptr [edx-08]
:00450129 setz al
:0045012C call 004092A0
Po porownaniu, w przypadku, gdy wartosci sa rowne, w al laduje 1. W przypadku tego programu nie wystarczy jednak zwykla zmiana setz na setnz. Problem porownania rozwiazac trzeba wczesniej. Wartosc w EAX to checksuma wyliczona z na podstawie naszego pliku. Wartosc pod adresem wskazywanym przez [EDX-8] to checksuma oczekiwana (czyli taka, jaka powinna zostac wyliczona, gdyby w pliku nie dokonano zadnych zmian). Musimy zrobic cos, by suma wyliczona rowna by│a sumie oczekiwanej. Jak zawsze rozwiazan jest wiele, rozne ich kombinacje pozostawiam twojwj wyobrazni. Ja zaproponuje jedno. Zatrzymajmy siΩ na chwile w linii :00450126, tuz przed porownaniem obu checksum. Spojrz na EAX. Wartosc w EAX, czyli checksuma wyliczona, bedzie w kazdym przypadku inna (w zaleznosci od wprowadzonych zmian). Wartosc oczekiwana (d edx-8) wyniesie jednak zawsze tyle samo, czyli D3670CA6. Fajnie by bylo, gdyby w EAX znajdowala siΩ wlasnie taka wartosc. Zaden problem. Spojrz na linie :0045024D. Tutaj dokona zostaje ostateczne wyliczenie naszej checksumy (dotychczasowa XORowana jest z wartoscia F5A3E289). Czemu wiec nie zmienic tej linii z:
xor dword ptr [eax-04], F5A3E289
na:
mov dword ptr [eax-04], D3670CA6
(w hex zamieniamy - pod offsetem 4F64D - 8170FC89E2A3F5 na C740FCA60C67D3).
Po tym zabiegu checksumy bΩd╣ sobie rowne!
Zrobione. Mysle, ze teraz usuniecie 'Please register!' z okienka na poczatku i z helpa bedzie tylko formalnoscia.
Jezeli cos jest dla ciebie nadal niejasne, przeczytaj tutorial jeszcze raz, jesli to nie pomoze - napisz do mnie.